package com.jh.user.business.impl;

import cn.jh.common.exception.ServiceException;
import cn.jh.common.utils.BeanUtil;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.common.collect.Multimap;
import com.jh.user.business.BrandManageBusiness;
import com.jh.user.pojo.*;
import com.jh.user.pojo.enums.UserGrade;
import com.jh.user.repository.*;
import com.jh.user.service.BrandRateRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.EntityManager;
import javax.persistence.criteria.Path;
import javax.persistence.criteria.Predicate;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Service
public class BrandManageBusinessImpl implements BrandManageBusiness{

	@Autowired
	private BrandRateRepository brandRateRepository;

	@Autowired
	private BrandRepository brandRepository;

	@Autowired
	private BrandResourceRepository brandResourceRepository;

	@Autowired
	private BrandCoinRepository brandCoinRepository;

	@Autowired
	private ResourceRepository  resourceRepository;

	@Autowired
	private UserBankJhKeyRepository userBankJhKeyRepository;

	@Autowired
	private ChannelRateRepository channelRateRepository;

	@Autowired
	private EntityManager em;
	@Autowired
	private ChannelRepository channelRepository;

	@Override
	public Brand findBrandById(long id) {
		Brand  brand;
		brand= brandRepository.findBrandByid(id);
		return brand;
	}

	@Override
	public  List<Brand>   findAllBrand(){
		List<Brand>   brands=new ArrayList<Brand>();

		brands=brandRepository.findAllBrand();
		return brands;
	}

	@Transactional
	@Override
	public Brand mergeBrand(Brand brand) throws ServiceException {
		Brand brandByUserid = brandRepository.findBrandByUserid(brand.getManageid());
		if (null != brandByUserid) {
			throw new ServiceException("该用户已添加贴牌，不可建立多个贴牌！");
		}
		Brand result = brandRepository.save(brand);
		em.flush();
		return result;
	}
	@Override
	public UserBrandJhKey findBrandJhKeyById(long brandid, String keyPlan) {

		UserBrandJhKey jhKey =userBankJhKeyRepository.findBankJhKeyByIds(brandid,keyPlan);
		//UserBrandJhKey jhKey =userBankJhKeyRepository.findByBrandIdAndKeyPlan(brandid,keyPlan);
		return jhKey;
	}
	@Override
	public UserBrandJhKey findByBrandIdAndKeyPlan(long brandid, String keyPlan) {

		//UserBrandJhKey jhKey =userBankJhKeyRepository.findBankJhKeyByIds(brandid,keyPlan);
		UserBrandJhKey jhKey =userBankJhKeyRepository.findByBrandIdAndKeyPlan(brandid,keyPlan);
		return jhKey;
	}

	public List<UserBrandJhKey> findByBrandIdAndKeyList(long brandid){
		return userBankJhKeyRepository.findByBrandId(brandid);
	}

	@Override
	public Brand  mergeBrandNumber(String number) {
		Brand result = brandRepository.findBrandNumber(number);
		return result;
	}

	@Override
	public List<Brand> findBrandByName(String name) {
		return brandRepository.findBrandByName(name);
	}

	@Override
	public Brand findBrandByManageid(long manageid) {
		return brandRepository.findBrandByUserid(manageid);
	}

	@Override
	public  List<Brand>  findBrandByManageids(Long[]  manageids){
		List<Brand>  brands= new ArrayList<Brand>();
		brands=brandRepository.findBrandByUserids(manageids);

		return brands;
	}

	@Transactional
	@Override
	public BrandRate mergeBrandRate(BrandRate brandRate) {
		BrandRate result  = brandRateRepository.save(brandRate);
		em.flush();
		em.clear();
		return result;
	}

	@Override
	public BrandRate findRateByBrandAndChannel(long brandid, long channelid, String userGrade, Short payType,String channelMerType) {
		return brandRateRepository.findBrandRate(brandid, channelid, UserGrade.of(Integer.valueOf(userGrade)), payType,channelMerType);
	}

	@Override
	public BrandRate findRateByBrandAndChannel(long brandid, long channelid, String userGrade, Short payType) {
		return brandRateRepository.findBrandRate(brandid, channelid, UserGrade.of(Integer.valueOf(userGrade)), payType);
	}

	@Override
	public List<BrandRate> findRateByBrandAndChannel(Multimap<Long, Long> brandIdsAndChannelIds) {
		if (brandIdsAndChannelIds == null || brandIdsAndChannelIds.isEmpty()) {
			return ImmutableList.of();
		}
		Specification<BrandRate> spec = (root, query, cb) -> {
			Path<Long> brandIdPath = root.get("brandId");
			Path<Long> channelIdPath = root.get("channelId");
			Predicate predicate = null;
			for (Map.Entry<Long, Long> entry: brandIdsAndChannelIds.entries()) {
				if (predicate == null) {
					predicate = cb.and(cb.equal(brandIdPath, entry.getKey()), cb.equal(channelIdPath, entry.getValue()));
				} else {
					predicate = cb.or(predicate, cb.and(cb.equal(brandIdPath, entry.getKey()), cb.equal(channelIdPath, entry.getValue())));
				}
			}
			return predicate;
		};
		return brandRateRepository.findAll(spec);
	}

	@Override
	public List<BrandRate> findRateByBrand(long brandid) {

		List<BrandRate> brandRateList=brandRateRepository.findBrandRateBybrandid(brandid);

		return brandRateList;
	}

	@Override
	public List<Resource> findResourceByBrand(long brandid) {

		return brandResourceRepository.findBrandResourceBybrandid(brandid);
	}

	@Transactional
	@Override
	public void delResourceByBrand(long brandid, long resourceid) throws Exception{
		brandResourceRepository.delResourceByBrandidAndResource(brandid, resourceid);
	}

	@Override
	public BrandResource saveBrandResource(BrandResource brandResource) {
		BrandResource result =  brandResourceRepository.save(brandResource);
		em.flush();
		return result;
	}

	@Override
	public List<Resource> findAllResource() {
		// TODO Auto-generated method stub
		return resourceRepository.findAllResource();
	}

	@Transactional
	@Override
	public Resource mergeResource(Resource resource) {
		Resource result = resourceRepository.save(resource);
		em.flush();
		return result;
	}

	@Transactional
	@Override
	public void delResource(long resourceid) {
		resourceRepository.delResource(resourceid);
	}

	@Override
	public BrandCoin findBrandCoin(long brandid) {
		// TODO Auto-generated method stub
		return brandCoinRepository.findBrandCoinBybrandid(brandid);
	}

	@Transactional
	@Override
	public BrandCoin addBrandCoin(BrandCoin Brandcoin) {
		BrandCoin result =  brandCoinRepository.save(Brandcoin);
		em.flush();
		return result;
	}

	@Transactional
	@Override
	public void updateBrandMange(long brandid, String branddescription) {
		brandRepository.updateBrandDescription(brandid, branddescription);
	}

	@Override
	public Brand findByUserIdAndBrandId(long userId, long brandid) {
		return brandRepository.findByManageidAndId(userId,brandid);
	}

	@Transactional
	@Override
	public BrandRate updateBrandRate(BrandRateRequest rateRequest, BigDecimal minrate) throws ServiceException {
		BrandRate brandRate = brandRateRepository.findBrandRate(rateRequest.getBrandId(),
				rateRequest.getChannelId(), rateRequest.getUserGrade(), rateRequest.getType(),rateRequest.getMerType());
		if (brandRate == null) {
			brandRate = BrandRate.init(rateRequest);
		} else {
			if (brandRate.getId() != rateRequest.getId()) {
				throw new ServiceException("指定修改的公共费率有误");
			}
			if (rateRequest.getRate() == null && rateRequest.getMinRate() != null &&
					rateRequest.getMinRate().compareTo(brandRate.getRate()) > 0) {
				throw new ServiceException("最低费率不能大于已有的贴牌费率");
			}

			// 个人费率 >= 推广人费率 >= 贴牌费率 >= 平台费率 >= 上游通道费率
			BigDecimal rate = rateRequest.getRate();
			BigDecimal gradeRate = rateRequest.getGradeRate();
			Long channelId = rateRequest.getChannelId();
			Channel channel = channelRepository.findChannelChannelNo(String.valueOf(channelId));
			BigDecimal costRate = new BigDecimal(channel.getCostRate());

			if (gradeRate.compareTo(rate) > 0) {
				throw new ServiceException("推荐人分润费率不能大于费率！");
			}
			if (minrate.compareTo(gradeRate) > 0) {
				throw new ServiceException("最小费率不能大于推荐人分润费率");
			}
			if (costRate.compareTo(minrate) > 0) {
				throw new ServiceException("平台最小费率必须大于通道费率！");
			}

			// 查询通道费率信息，修改通道费率和更新前的公共费率一致的费率信息
            // 如果数据量大，请采用分页查询，否则直接查集合就可以了
			synchronousChannelRate(brandRate, rateRequest);
		}
		brandRate.supply(rateRequest);
		brandRateRepository.saveAndFlush(brandRate);
		return brandRate;
	}

	/**
     * 公共费率修改时，同步对应的通道费率
     * 同步条件：RateRequest中rate、extraFee和gradeRate三个参数有请求修改，
     * 同时channelRate中这三个值和brandRate中的对应三个值有相同的，就视之为取得公共费率的值，
     * 在公共费率修改的同时，通道费率对应也需要修改；若值不同则视为用户特有的，保留
     *
     * @param brandRate 未修改之前的公共费率信息
     * @param rateRequest 修改请求数据
     */
	private void synchronousChannelRate(BrandRate brandRate, BrandRateRequest rateRequest) {
        Specification<ChannelRate> spec = (root, query, cb) -> {
            Path<Long> brandIdPath = root.get("brandId");
            Path<Long> channelIdPath = root.get("channelId");
            Path<Short> payTypePath = root.get("payType");

			Path<String> channelMerTypePath = root.get("channelMerType");
            return cb.and(cb.equal(brandIdPath, brandRate.getBrandId()),
                    cb.equal(channelIdPath, brandRate.getChannelId()),
                    cb.equal(payTypePath, brandRate.getPayType()),
					cb.equal(channelMerTypePath, brandRate.getChannelMerType()));
        };
        int currPage = 0;
        Pageable pageable;
        while (true) {
            pageable = new PageRequest(currPage,200);
            Page<ChannelRate> pageResult = channelRateRepository.findAll(spec, pageable);
            if (!pageResult.hasNext()) {
            	break;
			}
			currPage +=1;
            List<ChannelRate> channelRateList = pageResult.getContent();
            List<ChannelRate> updateList = Lists.newArrayList();
            for (ChannelRate channelRate: channelRateList) {
                boolean isUpdate = false;
                if (ChannelRate.checkIfUpdate(channelRate.getRate(), brandRate.getRate(), rateRequest.getRate())) {
                    channelRate.setRate(rateRequest.getRate());
                    isUpdate = true;
                }
                if (ChannelRate.checkIfUpdate(channelRate.getExtraFee(), brandRate.getExtraFee(), rateRequest.getExtraFee())) {
                    channelRate.setExtraFee(rateRequest.getExtraFee());
                    isUpdate = true;
                }
                if (ChannelRate.checkIfUpdate(channelRate.getGradeRate(), brandRate.getGradeRate(), rateRequest.getGradeRate())) {
                    channelRate.setGradeRate(rateRequest.getGradeRate());
                    isUpdate = true;
                }
                if (isUpdate) {
                    updateList.add(channelRate);
                }
            }
            channelRateRepository.save(updateList);
        }
    }

    @Override
    public List<BrandRate> findBrandRate(BrandRateRequest rateRequest) {
        return brandRateRepository.findBrandRate(rateRequest.getBrandId(), rateRequest.getChannelId(), rateRequest.getType(),rateRequest.getMerType());
    }

	@Override
	@Transactional
	public Brand updateBrand(Brand brand) throws ServiceException {
		Brand existBrand = brandRepository.findBrandByid(brand.getId());
		if (null == existBrand) {
			throw new ServiceException("无该贴牌信息！");
		}
		BeanUtil.copyPropertiesIgnoreNull(brand, existBrand);
		em.merge(existBrand);
		em.flush();
		return existBrand;
	}
}
